package com.sdhs.paas.sdk.core.web;

import java.io.IOException;
import java.nio.charset.Charset;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.UnknownHttpStatusCodeException;

import com.fasterxml.jackson.core.type.TypeReference;
import com.sdhs.paas.sdk.core.PaasBaseResponse;
import com.sdhs.paas.sdk.core.PaasDefaultObject;
import com.sdhs.paas.sdk.core.utils.JSONUtils;

public class PaasResponseErrorHandler implements ResponseErrorHandler {

	@Override
	public boolean hasError(ClientHttpResponse response) throws IOException {
		return hasError(getHttpStatusCode(response));
	}

	@Override
	public void handleError(ClientHttpResponse response) throws IOException {
		HttpStatus statusCode = getHttpStatusCode(response);
		switch (statusCode.series()) {
		case CLIENT_ERROR:
		case SERVER_ERROR:
			throw new PaasHttpServerErrorException(getResponsePojo(response));
		default:
			throw new RestClientException("Unknown status code [" + statusCode + "]");
		}
	}

	private HttpStatus getHttpStatusCode(ClientHttpResponse response) throws IOException {
		try {
			return response.getStatusCode();
		} catch (IllegalArgumentException ex) {
			throw new UnknownHttpStatusCodeException(response.getRawStatusCode(), response.getStatusText(),
					response.getHeaders(), getResponseBody(response), getCharset(response));
		}
	}

	private boolean hasError(HttpStatus statusCode) {
		return (statusCode.series() == HttpStatus.Series.CLIENT_ERROR
				|| statusCode.series() == HttpStatus.Series.SERVER_ERROR);
	}

	private Charset getCharset(ClientHttpResponse response) {
		HttpHeaders headers = response.getHeaders();
		MediaType contentType = headers.getContentType();
		return (contentType != null ? contentType.getCharset() : null);
	}

	private byte[] getResponseBody(ClientHttpResponse response) {
		try {
			return FileCopyUtils.copyToByteArray(response.getBody());
		} catch (IOException ex) {
			// ignore
		}
		return new byte[0];
	}

	private PaasBaseResponse<PaasDefaultObject> getResponsePojo(ClientHttpResponse response) {
		try {
			return JSONUtils.json2pojo(getResponseBody(response),
					new TypeReference<PaasBaseResponse<PaasDefaultObject>>() {
					});
		} catch (Exception e) {
			// ignore
		}
		return null;
	}

}
